﻿using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using common;

namespace Utem.Client
{
    public partial class FormClientView : Form
    {
        private int _port = 9011;
        private IPAddress _address = null;
        private readonly ServerConnectionInfo _serverConnectionInfo = FileUtils.GetConnectionInfo();
        private PlayerInfo _playerInfo = new PlayerInfo();
        private QuestionManagement _question = new QuestionManagement();
        private bool _isStop;
        private int _bonusTime = 0;
        private bool _isTesting = false;
        private string _selected = string.Empty;
        private int _no;
        private int _mark;
        private int _id = -1;
        private bool _canContinuteTest = true;
        private bool _isBeginBPlan = false;
        private bool _canClick = false;

        public FormClientView()
        {
            InitializeComponent();
        }

        private void FormClientView_Load(object sender, EventArgs e)
        {
            IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
            CheckForIllegalCrossThreadCalls = false;
            foreach (var ipAddress in localIPs)
            {
                if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
                {
                    _address = ipAddress;
                    break;
                }
            }
            labelStatus.Text = string.Empty;
            labelMark.Text = @"0";
            ShowHideQuestion(false);
            EnableChooseAnswer(false);
            _canContinuteTest = false;
        }

        private void ActionController(string action)
        {
            try
            {
                // Get 3 first characters.
                var temp = action.Substring(0, 3);
                string[] strs = null;
                int newMark = 0;
                switch (temp)
                {
                    case "200": // Get name form server
                        strs = action.Split(':');
                        labelName.Text = strs[1];
                        _playerInfo.Name = strs[1];
                        SendMessage(string.Format("201:{0} in {1} connected.", strs[1], _address.ToString()));
                        _id = int.Parse(strs[2]);
                        labelMark.Text = _mark.ToString();
                        labelStatus.Text = @"Received name from server.";
                        ResetSetting();
                        break;
                    case "300": // Receive question from server.
                        if (!_canContinuteTest) return;
                        var str = action.Substring(4);
                        _question = _question.DecodeQuestion(str);
                        _no++;
                        labelStatus.Text = @"Received question from server.";
                        ShowHideQuestion(false);
                        break;
                    case "301": //Start
                        if (!_canContinuteTest) return;
                        strs = action.Split(':');
                        _isStop = false;
                        ShowHideQuestion(true);
                        labelQuestionNo.Text = _no.ToString();
                        LoadQuestion();
                        StartCountDown(int.Parse(strs[1]));
                        labelStatus.Text = @"Begin your test";
                        _selected = string.Empty;
                        break;
                    case "302": // Abort
                        if (!_canContinuteTest) return;
                        _isStop = true;
                        EnableChooseAnswer(false);
                        labelStatus.Text = @"Time is up.";
                        break;
                    case "303": // Add Bonus time
                        if (!_canContinuteTest) return;
                        strs = action.Split(':');
                        _bonusTime = int.Parse(strs[1]);
                        labelStatus.Text = @"Server give you a bonus time: " + _bonusTime;
                        break;
                    case "304":
                        if (!_canContinuteTest) return;
                        strs = action.Split(':');
                        newMark = int.Parse(strs[1]);
                        _mark += int.Parse(strs[1]);
                        labelMark.Text = _mark.ToString(CultureInfo.InvariantCulture);
                        labelStatus.Text = string.Format("You got {0} mark from server.", newMark);
                        break;
                    case "305":
                        labelStatus.Text = string.Format("Congratulation! You are a winner!!!");
                        ShowHideQuestion(false);
                        _canContinuteTest = false;
                        break;
                    case "306":
                        labelStatus.Text = string.Format("Sorry! You are lose!!! :3");
                        ShowHideQuestion(false);
                        _canContinuteTest = false;
                        break;
                    case "307": // Begin B Plan
                        labelStatus.Text = string.Format("Ready");
                        _isBeginBPlan = true;
                        var currentTime = TimeSpan.Parse(DateTime.Now.ToShortTimeString());
                        strs = action.Split(':');
                        var nextTime = TimeSpan.Parse(strs[1]);
                        var duration = nextTime - currentTime;
                        CountDown(int.Parse(duration.TotalSeconds.ToString(CultureInfo.InvariantCulture)));
                        break;
                    case "308":
                        if (!_canContinuteTest) return;
                        strs = action.Split(':');
                        newMark = int.Parse(strs[1]) - int.Parse(labelMark.Text);
                        _mark = int.Parse(strs[1]);
                        labelMark.Text = _mark.ToString(CultureInfo.InvariantCulture);
                        labelStatus.Text = string.Format("You got {0} mark from server.", newMark);
                        break;
                }
            }
            catch (Exception ex)
            {
                SendMessage(string.Format("404:{0}:{1}", ex.Message, _playerInfo.Name));
            }
        }

        private void ResetSetting()
        {
            _no = 0;
            _mark = 0;
            _canContinuteTest = true;
            ShowHideQuestion(false);
            labelMark.Text = @"0";
        }

        private void LoadQuestion()
        {
            ShowHideQuestion(true);
            txtQuestion.Text = _question.Question;
            rbtnAnswer1.Text = @"A";
            lbAnsA.Text = _question.Answers[0];
            lbAnsB.Text = _question.Answers[1];
            rbtnAnswer2.Text = @"B";
            lbAnsC.Text = _question.Answers[2];
            rbtnAnswer3.Text = @"C";
            lbAnsD.Text = _question.Answers[3];
            rbtnAnswer4.Text = @"D";
        }

        private void ShowHideQuestion(bool isShow)
        {
            labelQuestionNo.Visible = isShow;
            txtQuestion.Visible = isShow;
            rbtnAnswer1.Visible = isShow;
            rbtnAnswer2.Visible = isShow;
            rbtnAnswer3.Visible = isShow;
            rbtnAnswer4.Visible = isShow;
            lbAnsA.Visible = isShow;
            lbAnsB.Visible = isShow;
            lbAnsC.Visible = isShow;
            lbAnsD.Visible = isShow;
        }


        private void StartListen()
        {
            var listener = new TcpListener(_address, _port);
            listener.Start();
            while (true)
            {
                try
                {
                    var st = new StreamReader(listener.AcceptTcpClient().GetStream());
                    CheckForIllegalCrossThreadCalls = false;
                    ActionController(st.ReadToEnd());
                    st.Close();
                }
                catch (Exception)
                {
                    RaiseErrorMessage();
                }
            }
        }

        private void SendMessage(string message)
        {
            try
            {
                var client = new TcpClient(_serverConnectionInfo.Ip, _serverConnectionInfo.Port);
                var sw = new StreamWriter(client.GetStream());
                sw.Write(message);
                sw.Flush();
                sw.Close();
            }
            catch (Exception ex)
            {
                RaiseErrorMessage();
            }
        }

        private static void RaiseErrorMessage()
        {
            MessageBox.Show(@"Connect error!!! Please contact administrator, NOW!!!", @"ERROR",
                   MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            _port = int.Parse(txtPort.Text);
            var ts = new ThreadStart(StartListen);
            var th = new Thread(ts);
            th.Start();
            SendMessage(string.Format("{0}:{1} joinned.", _address, _port));
        }

        private void button2_Click(object sender, EventArgs e)
        {
            StartCountDown(5);
        }

        private void StartCountDown(int max)
        {
            var ts = new ThreadStart(() => CountDown(max));
            var th = new Thread(ts);
            th.Start();
        }

        private void CountDown(int count)
        {
            CheckForIllegalCrossThreadCalls = false;
            labelTimer.ForeColor = Color.Black;
            labelTimer.BackColor = Color.Transparent;
            _isTesting = true;
            EnableChooseAnswer(true);
            while (count >= 0)
            {
                if (_isStop) count = 0;
                if (_bonusTime != 0)
                {
                    count += _bonusTime;
                    _bonusTime = 0;
                }
                var time = TimeSpan.FromSeconds(count);
                labelTimer.Text = string.Format("{0:D2}:{1:D2}", time.Minutes, time.Seconds);
                Thread.Sleep(1000);
                count--;
                if (count == 3)
                {
                    labelTimer.ForeColor = Color.White;
                    labelTimer.BackColor = ColorTranslator.FromHtml("#ff9036");
                }
                else if (count == 2)
                {
                    labelTimer.BackColor = ColorTranslator.FromHtml("#ff6a36");
                }
                else if (count == 1)
                {
                    labelTimer.BackColor = ColorTranslator.FromHtml("#ff0000");
                }
                else if (count == -1)
                {
                    _isTesting = false;
                    if (_isBeginBPlan)
                    {

                    }
                    else
                    {
                        SendMessage("310:" + _playerInfo.Name);
                        EnableChooseAnswer(false);
                        MessageBox.Show(@"Time is up", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1);
                    }
                }
            }
        }

        private void txtQuestion_MouseClick(object sender, MouseEventArgs e)
        {
            txtQuestion_KeyDown(null, null);
        }

        private void txtQuestion_KeyDown(object sender, KeyEventArgs e)
        {

        }

        private void rbtnAnswer1_CheckedChanged(object sender, EventArgs e)
        {
            if (!_isTesting) return;
            if (_selected.Equals("A")) return;
            _selected = "A";
            SendMessage(string.Format("205:A:{0}", _id));
        }

        private void rbtnAnswer2_CheckedChanged(object sender, EventArgs e)
        {
            if (!_isTesting) return;
            if (_selected.Equals("B")) return;
            _selected = "B";
            SendMessage(string.Format("205:B:{0}", _id));
        }

        private void rbtnAnswer3_CheckedChanged(object sender, EventArgs e)
        {
            if (!_isTesting) return;
            if (_selected.Equals("C")) return;
            _selected = "C";
            SendMessage(string.Format("205:C:{0}", _id));
        }

        private void rbtnAnswer4_CheckedChanged(object sender, EventArgs e)
        {
            if (!_isTesting) return;
            if (_selected.Equals("D")) return;
            _selected = "D";
            SendMessage(string.Format("205:D:{0}", _id));
        }

        private void EnableChooseAnswer(bool isEnable)
        {
            rbtnAnswer1.Enabled = isEnable;
            rbtnAnswer2.Enabled = isEnable;
            rbtnAnswer3.Enabled = isEnable;
            rbtnAnswer4.Enabled = isEnable;
        }

    }
}
